MidiGlock {
	var io;
	var <testing;
	var debugWin;
	var displays;
	var <fqs;
	var <buffs;
	var <>sens;
	var <ranges;
	var <>strips;
	var <>hooks;
	var <midiChan;
	var <monitor;

	*new {
		^super.new.init();
	}
	
	init {
		testing = Platform.case (
			{ \osx }, { false },
			{ \linux }, { true } );
		
		fqs = [ 860, 1100, 1700, 1975, 2793, 3729, 4698, 6271 ];
		ranges = [
			( 38 .. 43 ), ( 50 .. 53 ), ( 78 .. 81 ), ( 90 .. 95 ),
			( 128 .. 133 ), ( 172 .. 175 ), ( 216 .. 221 ), ( 290 .. 293 )
		];
		sens = 0.005!8!8;
		strips = 0!8;
		monitor = Routine{
			var result;
			var getbuffs = { | count, allbuffs |
				if( count < 8,
					{
						buffs[ count ].getn( 0, 1024, {
							| buff |
							getbuffs.( count + 1, allbuffs ++ [ buff ] ) } ) },
					{
						result = 0!8!8;
						allbuffs.do {
							| buff, i |
							ranges.do{
								| range, j |
								range.do{ | k |
									result[ i ][ j ] = (
										buff[ k ]+result[ i ][ j ] ) } } };
						result.do{ | y, i |
							MgState.reportHooks.do{ | f | f.col( y ) };
							y.do{ | z, j |
								MgState.reportHooks.do{
									| f | f.ele( z, i, j ) } } };
						MgState.reportHooks.do{
							| f | f.raw( result ) } } ) };
			loop { getbuffs.( 0, [] ); 0.3.wait } };
	}

	start { | action |
		Routine( {
			this.serverInit;
			5.wait;
			this.midiInit;
			5.wait;
			Tones.initClass( midiChan );
			1.wait;
			action.value( this ) } ).play;
	}

	serverInit {
		var serv = if( testing, Server.default, Server.internal );
		serv.waitForBoot{
			buffs = 8.collect{ Buffer.alloc( serv, 1024, 1 ) };
			if( testing, {
				SwingOSC.program="/usr/local/bin/SwingOSC.jar";
				//SwingOSC.java = "/usr/lib/jvm/java-1.5.0-sun-1.5.0.17/bin/java";
				SwingOSC.default.waitForBoot {
					debugWin = Window( "signal debug",
						Rect( -1, -1, 8*64, 8*64 ) );
					displays = 8.collect{
						| x |
						8.collect{
							| y |
							StaticText( debugWin,
								Rect( x*64, y*64, 64, 64 )).string_( 0 ) } };
					debugWin.front;
				}
			}, {
				FreqScope( busNum: 0 );
				SynthDef( \io, {
					var result = SoundIn.ar( ( 0..7 ) );
					8.do{
						| n | 
						Out.ar( n, SinOsc.ar( fqs[ n ] ) );
						FFT( buffs[ n ], result[ n ] ) } } ).send( serv ) } ) };
	}

	midiInit {
		var uid;
		var touched = 0!8;
		if( testing, {
			MIDIClient.init( 1, 1 );
			uid = 1048576;
			midiChan = MIDIOut( 0, uid );
			midiChan.latency_( 0 );
		}, {
			MIDIClient.init;
			uid = MIDIClient.destinations[ 0 ].uid;
			midiChan = MIDIOut( 0, uid );
		} );
		midiChan.connect( uid );
		Melody.initClass( midiChan );
		if( not( testing ), {
			io = Synth( \io );
		}, { 
			CCResponder( {
				| src, ch, num, val |
				//var strip = ch; // for bcf2000 preset 3
				var strip = ( num - 1 ) % 8; // for my custom nanocontrol config
				var adjusted = val**4 * 0.00000005;
				var getbuffs = { | count, allbuffs |
					if( count < 8,
						{
							buffs[ count ].getn( 0, 1024, { | buff |
								getbuffs.( count + 1, allbuffs ++ [ buff ] ) } )
						},
						{
							touched.do{ | tn, i |
								ranges[ strip ].do{ | elt |
									allbuffs[ i ][ elt ] =
									tn.rand + adjusted.rand };
								ranges[ i ].do{ | elt |
									allbuffs[ strip ][ elt ] =
									tn + ( adjusted.rand + adjusted.rand ) / 2;
								} };
							allbuffs.do{ | buff, i |
								buffs[ i ].setn( 0, buff ) } } ) };
				touched[ strip ] = adjusted;
				getbuffs.( 0, [] ) } ) } );
	}

	show { | i, j, bg, fg, num |
		displays[ i ][ j ].background = bg;
		displays[ i ][ j ].stringColor = fg;
		displays[ i ][ j ].string = num;
	}

	stop {
		if( io.notNil, {
			io.free;
			io = nil;
		} );
		monitor.stop;
	}

	// *normalizeStrips { | strips |
	// 	var modified = false;
	// 	strips.size.collect
	// 	{ | i |
	// 		strips.size.do
	// 		{ | j |
	// 			if ( and( i != j, sect( strips[ i ], strips[ j ] ).size > 0 ),
	// 				{
	// 					modified = true;
	// 					strips[ i ] = union( strips[ i ], strips[ j ] );
	// 					strips[ j ] = Set[] } ) } };
	// 	strips = strips.select { | st | st.size > 0 };
	// 	if( modified,
	// 		{ MidiGlock.normalizeStrips.( strips ) },
	// 		strips )
	// }
}
